<?php
if( !defined('IN_SEC') ){
	exit('Access Denied.');
}

class DB{

	public static $instance = null;
	public static $link = null;
	public static $count = 0;
	private static $result;
	private static $config;
	private static $querys;

	public static function &instance($setting = array()){
		if ( self::$instance == null ){
			self::$config = ($setting ? $setting : conf('db'));
			self::$instance = new DB;
		}
		return self::$instance;
	}

	public function __construct(){
		global $_G;
		self::$link = mysql_connect(self::$config['host'], self::$config['user'], self::$config['pass'], 1);
		if ( !self::$link ){
			self::halt('Can not connect to MySql server. Please check the db config.');
		}
		mysql_select_db(self::$config['name'], self::$link);
		mysql_query("SET NAMES UTF8", self::$link);
	}

	public static function query($sql){
		self::instance();
		self::$result = mysql_query($sql, self::$link);
		self::$count++;
		if ( !self::$result ){
			self::halt(array(), $sql);
		}
		self::$querys[] = $sql;
		return self::$result;
	}

	public static function querys(){
		return self::$querys;
	}

	public static function fetch_array($sql, $one = 0, $options = array(), $type = MYSQL_ASSOC){
		if ( $options['cachekey'] ){
			$cachekey = $options['cachekey'];
		}else{
			$cachekey = md5($sql);
		}
		if ( $cachekey ){
			if ( $cache = Cache::Get($cachekey) ){
				return $cache;
			}
		}

		self::query($sql);
		$result = array();
		while( $row = mysql_fetch_array(self::$result, $type) ){
			$row = array_change_key_case($row, CASE_LOWER);
			if ( $one ){
				$result = $row;
				break;
			}else{
				array_push($result, $row);
			}
		}
		mysql_free_result(self::$result);
		if ( $cachekey && $result ){
			$cachetime = intval($options['cachetime']);
			Cache::Set($cachekey, $result, $flag = 0, $cachetime);
		}
		return $result;
	}

	public static function fetch($table, $where = '', $options = array()){
		$sql = self::select($table, $where, $options);
		return self::fetch_array($sql, true, $options);
	}

	public static function limit($table, $where = '', $options = array()){
		$sql = self::select($table, $where, $options);
		return self::fetch_array($sql, 0, $options);
	}

	public static function count($table, $where = array(), $sum = '', $group = ''){
		$table = self::table($table);
		$where = $where ? self::where($where) : '';
		$zone = $sum ? "SUM({$sum})" : "COUNT(1)";
		$as = $group ? ",`{$group}`" : '';
		$group = $group ? "GROUP BY `{$group}` " : '';
		$sql = "SELECT {$zone} AS `count` {$as} FROM {$table} {$where} {$group}";
		$row = self::fetch_array($sql, $group ? 0 : 1);
		$data = $group ? $row : ($sum ? (0+$row['count']) : intval($row['count']));
		return $data;
	}

	public static function delete($table, $where = ''){
		$table = self::table($table);
		$where = self::where($where);
		$sql = "DELETE FROM {$table} {$where}";
		return self::query($sql);
	}

	public static function select($table, $where, $options){
		$options = is_array($options) ? $options : self::halt('Options is not Array');
		$table = $table ? self::table($table) : self::halt('No Table');
		$where = $where ? self::where($where) : '';
		$order = $options['order'] ? $options['order'] : '';
		$group = $options['group'] ? $options['group'] : '';
		$limit = $options['limit'] ? 'LIMIT ' . $options['limit'] : '';
		$select = $options['select'] ? $options['select'] : '*';
		$select = $options['count'] ? $options['count'] : $select;
		$offset = $options['offset'] ? abs(intval($options['offset'])) : 0;
		$size = $options['size'] ? abs(intval($options['size'])) : null;
		$limit = $size ? "LIMIT {$offset},{$size}" : $limit;
		return $sql = "SELECT {$select} FROM {$table} {$where} {$order} {$group} {$limit}";
	}

	public static function where($options, $logic = 'AND', $pre = 'WHERE'){
		$pre = $pre ? "{$pre} " : '';
		if ( is_array($options) ){
			$logic = strtoupper( $logic );
			$where = null;
			foreach( $options as $k => $v ){
				$string = null;
				$connect = '=';
				if ( is_numeric($k) ){
					$where .= ' ' . $logic . ' (' . self::where( $v, $logic, '') . ')';
					continue;
				}
				$k = preg_replace('/[^\w\-\_]+/', '', $k);
				$maybe_logic = strtoupper($k);
				if ( in_array($maybe_logic, array('AND', 'OR'))){
					$where .= ' ' . $logic . ' (' . self::where( $v, $maybe_logic, '') . ')';
					continue;
				}
				if ( is_numeric($v) ) {
					$string = "'{$v}'";
				}else if ( is_null($v) ) {
					$connect = ' IS';
					$string = ' NULL';
				}else{
					$string = "'" . self::EscapeString($v) . "'";
				}
				$where .= $where ? " {$logic} `{$k}` {$connect} {$string}" : "`{$k}` {$connect} {$string}";
			}
			$where = preg_replace('/^\s*' . $logic . '\s*/', '', $where);
			$where = preg_replace('/\s*' . $logic . '\s*$/', '', $where);
			$where = trim($where);
			return $where = "{$pre}{$where}";
		}else{
			return $where = "{$pre}{$options}";
		}
	}

	public static function table($table){
		self::instance();
		return '`' . self::$config['name'] . '`.`' . self::$config['tablepre'] . $table . '`';
	}

	public static function insert($table, $data = array()){
		$sql = "INSERT INTO " . self::build($table, $data);
		self::query($sql);
		return self::insertid();
	}

	public static function insertid(){
		return @mysql_insert_id(self::$link);
	}

	public static function update($table, $data = array(), $where = array()){
		$sql = "UPDATE " . self::build($table, $data, $where);
		return self::query($sql);
	}

	public static function build($table, $data, $where = array()){
		$table = $table ? self::table($table) : self::halt('No Table');
		$where = $where ? self::where($where) : '';

		$sql = "{$table} SET";
		$content = null;

		foreach( $data as $k => $v ){
			$string = null;
			if ( is_numeric($v) ){
				$string = "'{$v}'";
			}elseif( is_null($v) ){
				$string = 'NULL';
			}elseif( is_array($v)){
				$string = $v[0]; //for plus/sub/multi; 
			}else{
				$string = "'" . self::EscapeString($v) . "'";
			}
			$content .= " `{$k}` = {$string},";
		}

		$sql .= trim($content, ',') . ' ' . $where;

		return $sql;
	}

	static public function EscapeString($string = ''){
		self::instance();
		return @mysql_real_escape_string( $string, self::$link );
	}

	public static function error(){
		return mysql_error(self::$link);
	}

	public static function errno(){
		return mysql_errno(self::$link);
	}

	public static function close(){
		if( is_resource(self::$link) ){
			mysql_close(self::$link);
			self::$link = null;
			self::$instance = null;
		}
	}

	public static function halt($msg = '', $sql){
		$bug = new Bug();
		if ( is_array($msg) ){
			$msg = array(self::error(), self::errno());
		}
		$bug->db($msg, $sql);
	}

	public function __destruct(){
		self::close();
	}
}

?>